// Output Module
module output_module(clock, data_out, credit_in, valid_out, creditsOut);
	
	parameter data_width = 16;
	parameter credit_count = 8;
	parameter credit_width = ( (((credit_count)) ==0) ? 0 // - credit_count==0 LOG2=0
			: (((credit_count-1)>>0)==0) ? 0 // - credit_count<=1 LOG2=0
			: (((credit_count-1)>>1)==0) ? 1 // - credit_count<=2 LOG2=1
			: (((credit_count-1)>>2)==0) ? 2 // - credit_count<=4 LOG2=2
			: (((credit_count-1)>>3)==0) ? 3 // - credit_count<=8 LOG2=3
			: (((credit_count-1)>>4)==0) ? 4 // - credit_count<=16 LOG2=4
			: (((credit_count-1)>>5)==0) ? 5 // - credit_count<=32 LOG2=5
			: (((credit_count-1)>>6)==0) ? 6 // - credit_count<=64 LOG2=6
			: (((credit_count-1)>>7)==0) ? 7 // - credit_count<=128 LOG2=7
			: 8) // - credit_count<=256 LOG2=8
			;
	
	parameter addr_count = 16;
	parameter addr_width = ( (((addr_count)) ==0) ? 0 // - addr_count==0 LOG2=0
			: (((addr_count-1)>>0)==0) ? 0 // - addr_count<=1 LOG2=0
			: (((addr_count-1)>>1)==0) ? 1 // - addr_count<=2 LOG2=1
			: (((addr_count-1)>>2)==0) ? 2 // - addr_count<=4 LOG2=2
			: (((addr_count-1)>>3)==0) ? 3 // - addr_count<=8 LOG2=3
			: (((addr_count-1)>>4)==0) ? 4 // - addr_count<=16 LOG2=4
			: (((addr_count-1)>>5)==0) ? 5 // - addr_count<=32 LOG2=5
			: (((addr_count-1)>>6)==0) ? 6 // - addr_count<=64 LOG2=6
			: (((addr_count-1)>>7)==0) ? 7 // - addr_count<=128 LOG2=7
			: 8) // - addr_count<=256 LOG2=8
			;
	
	
	
	input clock;	
	output [data_width-1:0] data_out;
	input credit_in;
	output valid_out;
	output [credit_width:0] creditsOut;
	
	reg [data_width-1:0] mem [addr_count-1:0];
	

	assign data_out = mem[addr];
	reg [credit_width:0] credits;	// start with full credits
	//reg [2:0] credits;
	reg [addr_width:0] addr, last_addr;
	assign creditsOut = credits;
	
	initial begin
		credits <= credit_count;
		// synthesis loop_limit 256
		for(addr = 0; addr < addr_count; addr=addr+1) begin
			mem[addr] <= addr;
		end
		addr <= 0;
	end
	
	assign valid_out = (last_addr == addr) ? 0 : 1;
	
	
	always @(posedge clock) begin
		last_addr <= addr;	// retain the last address as a simple way of checking if we've sent data off
		
		if(credits > 1)
			addr <= (addr < addr_count - 1) ? addr + 1 : addr;	
		else
			addr <= addr;	// no change
		
		if(credit_in && (last_addr != addr) )	// we've sent something off but also received a credit
				credits <= credits;
		else if(credit_in && (last_addr == addr) )  
			credits <= credits + 1'b1;
		else if(~credit_in && (last_addr == addr) ) 
			credits <= credits;
		else if(~credit_in && (last_addr != addr) )
			credits <= credits - 1'b1;
		// the addr update logic eliminates need for credits bounds checking.
	end
	
	
endmodule
	
